package com.face.facerecognition.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.face.facerecognition.entity.AuthTokenStatus;
import com.face.facerecognition.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class BaiDuService {
    @Value("${baidu.planId}")
    private String planId;
    @Value("${baidu.faceAuthUrl}")
    private String faceAuthUrl;
    @Value("${baidu.callbackUrl}")
    private String callbackUrl;
    @Autowired
    private OkHttpClient okHttpClient;
    @Autowired
    private AuthService authService;
    @Autowired
    private AuthTokenStatusService authTokenStatusService;
    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;

    // 使用 ConcurrentHashMap 存储每个 token 对应的 ScheduledFuture
    private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();

    public String getRandomCode() throws IOException {
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType, "type=1&min_code_length=3&max_code_length=3");
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/face/v1/faceliveness/sessioncode?access_token=" + authService.getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();
        Response response = okHttpClient.newCall(request).execute();
        System.out.println(response.body().string());
        return response.body().toString();
    }


    public JSONObject verifyToken() throws IOException {
        MediaType mediaType = MediaType.parse("application/json");
        JSONObject planIdJson = new JSONObject();
        planIdJson.put("plan_id", planId);
        RequestBody body = RequestBody.create(mediaType, planIdJson.toString());
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/verifyToken/generate?access_token=" + authService.getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        Response response = okHttpClient.newCall(request).execute();
        return JSON.parseObject(response.body().string());
    }

    /**
     * 申报姓名，身份证，然后调用百度认证
     * userMap 字段 id_name，id_no
     *
     * @return
     * @throws IOException
     */
    public ResultVo uploadUserInfo(Map<String, Object> userMap) throws IOException {
        String accessToken = authService.getAccessToken();
        MediaType mediaType = MediaType.parse("application/json");
        //调用获取认证verifyToken接口才能后续上传用户信息
        JSONObject verifyTokenJson = verifyToken();
        log.info("verifyToken/generate接口调用结果：{}", verifyTokenJson);
        if (ObjectUtils.isEmpty(verifyTokenJson) || !verifyTokenJson.getBoolean("success")) {
            return ResultVo.error("获取认证verifyToken失败");
        }
        JSONObject verifyJson = verifyTokenJson.getJSONObject("result");
        String verify_token = verifyJson.getString("verify_token");
        userMap.put("verify_token", verify_token);
        // 证件类型：0:大陆居民二代身份证,4:港澳台居民居住证
        userMap.put("certificate_type", 0);
        RequestBody body = RequestBody.create(mediaType, org.json.JSONObject.wrap(userMap).toString());
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/idcard/submit?access_token=" + accessToken)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        Response response = okHttpClient.newCall(request).execute();
        String submitResult = response.body().string();
        JSONObject submitJson = JSON.parseObject(submitResult);
        log.info("idcard/submit接口调用结果：{}", submitJson);
        boolean result = submitJson.getBoolean("success");
        String baiduFaceAuthUrl = faceAuthUrl + verify_token + "&callbackUrl=" + callbackUrl + "?" + "token=" + verify_token;
        verifyJson.put("baiduFaceAuthUrl", baiduFaceAuthUrl);
        boolean saveFlag = false;
        if (result) {
            AuthTokenStatus authTokenStatus = new AuthTokenStatus();
            authTokenStatus.setToken(verify_token);
            authTokenStatus.setUserName(String.valueOf(userMap.get("id_name")));
            authTokenStatus.setIdCard(String.valueOf(userMap.get("id_no")));
            saveFlag = authTokenStatusService.save(authTokenStatus);
        }
        if (result && saveFlag) {
            scheduleAuthCheck(verify_token);
        }
        return result && saveFlag ? ResultVo.success(verifyJson) : ResultVo.error(submitJson.getString("message"));
    }


    /**
     * 获取是否认证完成
     * * //        {
     * * //    "success": false,
     * * //    "result": null,
     * * //    "code": 283450,
     * * //    "message": "认证尚未开始。Verification is not started yet.",
     * * //    "log_id": "1877630606465113529"
     * * //}
     *
     * @return
     * @throws IOException
     */
    public JSONObject getAuthResult(String token) throws IOException {
        MediaType mediaType = MediaType.parse("application/json");
        JSONObject tokenJson = new JSONObject();
        tokenJson.put("verify_token", token);
        RequestBody body = RequestBody.create(mediaType, tokenJson.toString());
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/result/detail?access_token=" + authService.getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .build();
        Response response = okHttpClient.newCall(request).execute();
        JSONObject authResult = JSON.parseObject(response.body().string());
        log.info("result/detail调用查询认证接口:{}", authResult);
        return authResult;
    }

    private void scheduleAuthCheck(String token) {
        int maxAttempts = 60; // 最大尝试次数
        AtomicInteger attemptCounter = new AtomicInteger(0); // 计数器
        ScheduledFuture<?> future = taskScheduler.scheduleAtFixedRate(() -> {
            try {
                log.info("开启定时调用认证结果token:{}",token);
                ScheduledFuture<?> currentFuture = scheduledFutures.get(token);
                // 检查是否达到最大尝试次数
                if (attemptCounter.incrementAndGet() >  maxAttempts) {
                    log.info("达到最大尝试次数:{}，移除当前定时任务token:{}",maxAttempts, token);
                    if (currentFuture != null) {
                        currentFuture.cancel(false);
                        scheduledFutures.remove(token);
                    }
                    return;
                }
                //查看是否为认证状态，已认证将取消定时任务以及后续逻辑
                if (authTokenStatusService.isAuthRealName(token) != null && currentFuture != null) {
                        currentFuture.cancel(false);
                        //移除当前的定时任务
                        log.info("已由回调地址响应认证状态，移除当前token:{}的定时任务",token);
                        scheduledFutures.remove(token);
                    return;
                }
                JSONObject authResult = getAuthResult(token);
                // 更新认证状态
                boolean isRealName = authTokenStatusService.updateStatusByToken(token, authResult);
                if(isRealName){
                    log.info("认证成功，移除当前token的定时任务:{}",token);
                    if (currentFuture != null) {
                        currentFuture.cancel(false);
                        scheduledFutures.remove(token);
                    }
                }


            } catch (IOException e) {
                log.error("定时执行调用 scheduleAuthCheck 失败", e);
            }
        }, 5000); // 每5秒执行一次

        // 将 ScheduledFuture 与 token 关联
        scheduledFutures.put(token, future);
    }
}
